package avicit.bdp.dms.oauth2.handler;

import avicit.bdp.dms.oauth2.OAuthTokenHandler;
import avicit.bdp.dms.oauth2.WebUtils;
import avicit.bdp.dms.oauth2.token.AccessToken;
import avicit.bdp.dms.oauth2.token.OauthTokenService;
import avicit.bdp.dms.oauth2.validator.AbstractClientDetailsValidator;
import avicit.bdp.dms.tdm.dto.AppClientDTO;
import avicit.platform6.core.spring.SpringFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;

/**
 * TODO
 *
 * @author xugb
 * @date 2024/4/12 14:45
 */

public abstract class AbstractOAuthTokenHandler implements OAuthTokenHandler {
    private static final Logger LOG = LoggerFactory.getLogger(AbstractOAuthTokenHandler.class);
    protected transient OauthTokenService oauthTokenService = SpringFactory.getBean(OauthTokenService.class);
    protected OAuthTokenRequest tokenRequest;
    protected HttpServletResponse response;
    private AppClientDTO appClientDTO;

    public AbstractOAuthTokenHandler() {
    }

    @Override
    public final void handle(OAuthTokenRequest tokenRequest, HttpServletResponse response) throws OAuthProblemException, OAuthSystemException {
        this.tokenRequest = tokenRequest;
        this.response = response;
        if (!this.validateFailed()) {
            this.handleAfterValidation();
        }
    }

    protected AppClientDTO clientDetails() {
        if (this.appClientDTO == null) {
            this.appClientDTO = this.oauthTokenService.getAppClientById(this.tokenRequest.getClientId());
        }

        return this.appClientDTO;
    }

    protected abstract AbstractClientDetailsValidator getValidator();

    protected OAuthResponse createTokenResponse(AccessToken accessToken) throws OAuthSystemException {
        AppClientDTO sysOauthClient = this.clientDetails();
        OAuthASResponse.OAuthTokenResponseBuilder builder = OAuthASResponse.tokenResponse(200).setAccessToken(accessToken.getAccessToken()).location(sysOauthClient.getRedirectUri()).setExpiresIn(String.valueOf(accessToken.currentTokenExpiredSeconds())).setTokenType("Bearer");
        String refreshToken = accessToken.getRefreshToken();
        if (StringUtils.isNotEmpty(refreshToken)) {
            builder.setRefreshToken(refreshToken);
        }

        return builder.buildJSONMessage();
    }

    protected boolean validateFailed() throws OAuthSystemException {
        AbstractClientDetailsValidator validator = this.getValidator();
        LOG.debug("Use [{}] validate client: {}", validator, this.tokenRequest.getClientId());
        OAuthResponse oAuthResponse = validator.validate();
        return this.checkAndResponseValidateFailed(oAuthResponse);
    }

    protected boolean checkAndResponseValidateFailed(OAuthResponse oAuthResponse) {
        if (oAuthResponse != null) {
            LOG.debug("Validate OAuthAuthzRequest(client_id={}) failed", this.tokenRequest.getClientId());
            WebUtils.writeOAuthJsonResponse(this.response, oAuthResponse);
            return true;
        } else {
            return false;
        }
    }

    protected String clientId() {
        return this.tokenRequest.getClientId();
    }

    protected abstract void handleAfterValidation() throws OAuthProblemException, OAuthSystemException;
}
